﻿using Elastic.Clients.Elasticsearch;
using Elastic.Transport;
using System.Diagnostics;
using System.IO;
using VideoTools.Commands;
using VideoTools.Extension;
using VideoTools.Util;
using VideoTools.vo;
using Log = Serilog.Log;
namespace VideoTools.Services
{
    public abstract class ISubtitleImportService
    {
        public ElasticsearchClient client;
        protected SubtitleSearchType searchType;
        protected Dictionary<string, SubtitleName> nameMap = new Dictionary<string, SubtitleName>();

        public ISubtitleImportService()
        {
            AppConfig config = AppConfig.Instance;
            var settings = new ElasticsearchClientSettings(new Uri(config.EsAddress))
                .CertificateFingerprint(config.EsFingerprint)
                .Authentication(
                    new BasicAuthentication(config.EsUserName, config.EsPassword)
                );
            client = new ElasticsearchClient(settings);
        }

        public Dictionary<string, SubtitleName> initName(
            string folder,
            IList<SubtitleImport> files,
            string address
        )
        {
            nameMap.Clear();
            Dictionary<string, int> nameCountMap = new Dictionary<string, int>();
            if (files != null)
            {
                if (searchType == SubtitleSearchType.Tv)
                {
                    foreach (var file in files)
                    {
                        string[] infos = file.FileName.Split("\\");
                        if (infos.Length > 1)
                        {
                            int count = 1;
                            if (nameCountMap.ContainsKey(infos[0]))
                            {
                                count += nameCountMap[infos[0]];
                                nameCountMap.Remove(infos[0]);
                            }
                            nameCountMap.Add(infos[0], count);
                        }
                    }
                }
                else
                {
                    foreach (var file in files)
                    {
                        //电影活着短视频直接使用文件名称
                        nameCountMap.Add(file.FileName.Replace(".srt", ""), 1);
                    }
                }
            }
            //不是批量方式
            if (nameCountMap.Keys.Count == 0)
            {
                string[] infos = folder.Split("\\");
                if (infos.Length > 1)
                {
                    nameCountMap.Add(infos[infos.Length - 1], files.Count);
                }
            }
            Dictionary<string, SubtitleName> insertList = new Dictionary<string, SubtitleName>();
            var response = client.Search<SubtitleName>(s =>
                s.Index(SearchSubtitleCommands.NAME_INDEX).From(0).Size(10000)
            );
            int maxId = 0;
            if (response.IsValidResponse)
            {
                IReadOnlyCollection<SubtitleName> documents = response.Documents;
                foreach (var sname in nameCountMap.Keys)
                {
                    SubtitleName name = new SubtitleName()
                    {
                        cateType = (byte)searchType,
                        cateDesc = searchType.Desc(),
                        name = sname,
                        nameId = 0,
                        count = 0,
                        chapterCount = nameCountMap[sname],
                        createTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    };
                    insertList.Add(sname, name);
                }
                if (response.HitsMetadata.Total.Value > 0)
                {
                    foreach (SubtitleName nm in documents)
                    {
                        foreach (var sname in nameCountMap.Keys)
                        {
                            if (nm.name.Equals(sname) && nm.cateType == (byte)searchType)
                            {
                                nameMap.Add(sname, nm);
                                insertList.Remove(sname);
                            }
                        }
                        maxId = int.Max(nm.nameId, maxId);
                    }
                }
            }
            else
            {
                throw new Exception("查询name出错");
            }
            if (insertList.Count == 0)
            {
                return nameMap;
            }

            List<SubtitleName> names = new List<SubtitleName>();
            foreach (var sname in insertList.Keys)
            {
                SubtitleName name = insertList[sname];
                name.nameId = ++maxId;
                nameMap.Add(name.name, name);
            }
            Elastic.Clients.Elasticsearch.BulkResponse bulkResponse = client.Bulk(bd =>
                bd.IndexMany(
                    names,
                    (descriptor, name) =>
                        descriptor.Index(SearchSubtitleCommands.NAME_INDEX).Id(name.nameId)
                )
            );
            if (bulkResponse.IsSuccess()) { }
            return nameMap;
        }

        public void insertAddress(List<SubtitleVideoAddress> addressList)
        {
            Elastic.Clients.Elasticsearch.BulkResponse bulkResponse = client.Bulk(bd =>
                bd.IndexMany(
                    addressList,
                    (descriptor, addr) =>
                        descriptor
                            .Index(SearchSubtitleCommands.ADDRESS_INDEX)
                            .Id(addr.vtype + "_" + addr.vid)
                )
            );
            if (bulkResponse.IsSuccess()) { }
        }
        public List<SubtitleVideoAddress> queryAddressDescIsNull()
        {
            var response = client.Search<SubtitleVideoAddress>(s =>
                s.Index("vaddress")
                    .From(0)
                    .Size(100)
                    .Sort(st =>
                        st.Field(
                            "vid",
                            f => f.Order(Elastic.Clients.Elasticsearch.SortOrder.Asc)
                        )
                    )
                    .Query(q => q.Bool(b => b.MustNot(m => m.Term(ma => ma.desc, ""))))
            );
            List<SubtitleVideoAddress> list = new List<SubtitleVideoAddress>();
            if (response.IsValidResponse)
            {
                IReadOnlyCollection<SubtitleVideoAddress> documents = response.Documents;
                foreach (SubtitleVideoAddress addr in documents)
                {
                    list.Add(addr);
                }
            }
            return list;
        }


        /// <summary>
        /// 获取类型
        /// </summary>
        /// <returns></returns>
        public SubtitleSearchType GetSearchType()
        {
            return searchType;
        }

        /// <summary>
        /// 打开文件或者目录
        /// </summary>
        /// <returns></returns>
        public abstract (string folder, List<string> files) open(bool batch = false);

        /// <summary>
        /// 解析字幕和id
        /// </summary>
        /// <param name="name"></param>
        /// <param name="fold"></param>
        /// <param name="file"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        public abstract (int count, SubtitleName name) importSubtitle(
            string folder,
            SubtitleImport file,
            string address
        );

        /// <summary>
        /// 更新总数
        /// </summary>
        /// <param name="nameMap"></param>
        public abstract void updateCount(Dictionary<string, SubtitleName> nameMap);

        public void assToSrt(string folder)
        {
            Process process = new Process();
            process.StartInfo.FileName = "asstosrt";
            process.StartInfo.WorkingDirectory = folder;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            Serilog.Log.Debug("ass转srt");
            process.StartInfo.CreateNoWindow = true; //显示命令行窗口
            //不使用操作系统使用的shell启动进程
            process.StartInfo.UseShellExecute = false;
            //将输出信息重定向
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.EnableRaisingEvents = true;

            process.OutputDataReceived += (o, e) => Serilog.Log.Information(e.Data ?? "NULL", e.Data);
            process.ErrorDataReceived += (o, e) => Serilog.Log.Information(e.Data ?? "NULL", e.Data);
            process.Exited += (o, e) => Serilog.Log.Information("Exited", "asstosrt");

            process.Start();
            //开始异步读取输出
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }
    }

    public class SubtitleImportTvService : ISubtitleImportService
    {
        private bool batch;

        public SubtitleImportTvService()
        {
            searchType = SubtitleSearchType.Tv;
        }

        public override (string folder, List<string> files) open(bool _batch = false)
        {
            this.batch = _batch;
            if (batch)
            {
                using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
                {
                    folderBrowserDialog.Description = "请选择一个文件夹";
                    DialogResult dialogResult = folderBrowserDialog.ShowDialog();

                    if (dialogResult != DialogResult.OK)
                    {
                        return (null, null);
                    }
                    string selectedFolder = folderBrowserDialog.SelectedPath;
                    DirectoryInfo directoryInfoParent = new DirectoryInfo(selectedFolder);
                    List<string> fileList = new List<string>();

                    foreach (DirectoryInfo di in directoryInfoParent.GetDirectories())
                    {
                        FileInfo[] fs = di.GetFiles();

                        foreach (FileInfo fileInfo in fs)
                        {
                            string directoryName = fileInfo.DirectoryName;
                            string[] infos = directoryName.Split("\\");
                            directoryName = infos[infos.Length - 1];
                            if (fileInfo.Name.ToLower().EndsWith(".srt"))
                            {
                                fileList.Add(directoryName + "\\" + fileInfo.Name);
                            }
                            else if (fileInfo.Name.ToLower().EndsWith(".ass"))
                            {
                                fileList.Add(
                                    directoryName
                                        + "\\"
                                        + fileInfo.Name.ToLower().Replace(".ass", ".srt")
                                );
                            }
                            else if (fileInfo.Name.ToLower().EndsWith(".ssa"))
                            {
                                fileList.Add(
                                    directoryName
                                        + "\\"
                                        + fileInfo.Name.ToLower().Replace(".ssa", ".srt")
                                );
                            }
                        }
                        assToSrt(di.FullName);
                    }
                    return (selectedFolder, fileList);
                }
            }
            else
            {
                List<string> fileList = new List<string>();
                OpenFileDialog openFileDialog = new OpenFileDialog();
                string filter = "字幕文件(*.srt,*.ass,*.ssa)|*.srt;*.ass;*.ssa";
                openFileDialog.Filter = filter;
                openFileDialog.RestoreDirectory = true;
                openFileDialog.FilterIndex = 1;
                openFileDialog.Multiselect = true;
                bool asstoserted = false;
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    string directoryName = null;
                    foreach (string filePath in openFileDialog.FileNames)
                    {
                        FileInfo fileInfo = new FileInfo(filePath);
                        directoryName = fileInfo.DirectoryName;
                        if (fileInfo.Name.ToLower().EndsWith(".srt"))
                        {
                            fileList.Add(fileInfo.Name);
                        }
                        else if (fileInfo.Name.ToLower().EndsWith(".ass"))
                        {
                            fileList.Add(fileInfo.Name.ToLower().Replace(".ass", ".srt"));
                        }
                        else if (fileInfo.Name.ToLower().EndsWith(".ssa"))
                        {
                            fileList.Add(fileInfo.Name.ToLower().Replace(".ssa", ".srt"));
                        }
                        if (!asstoserted)
                        {
                            assToSrt(directoryName);
                            asstoserted = true;
                        }
                    }
                    return (directoryName, fileList);
                }
            }
            return (null, null);
        }

        public override (int count, SubtitleName name) importSubtitle(
            string folder,
            SubtitleImport file,
            string address
        )
        {
            string[] infos = folder.Split("\\");
            string sname = infos[infos.Length - 1];
            if (batch)
            {
                infos = file.FileName.Split("\\");
                sname = infos[0];
            }
            SubtitleName name = nameMap[sname];
            string path = folder + "\\" + file.FileName;
            FileInfo fileInfo = new FileInfo(path);
            List<Subtitle> subtitles = SubtitleUtils.ReadSubtitle(fileInfo);
            List<SearchSubtitle> subtitleList = new List<SearchSubtitle>();
            foreach (Subtitle sub in subtitles)
            {
                SearchSubtitle subtitle = new SearchSubtitle()
                {
                    numb = sub.Number,
                    text = sub.Text,
                    start = $"{sub.StartTime:hh\\:mm\\:ss\\,fff}",
                    end = $"{sub.EndTime:hh\\:mm\\:ss\\,fff}",
                    nameId = name.nameId,
                    chapter = int.Parse(fileInfo.Name.ToLower().Replace(".srt", "")),
                };
                string _id = subtitle.nameId + "_" + subtitle.chapter + "_" + subtitle.numb;
                subtitleList.Add(subtitle);
                /*       Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle> ir
                           = new Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle>(subtitle, SubtitleSearchUI.SUBTITLE_INDEX, _id);
                       var responseSubtitle = client.Index(ir);
                       if (!responseSubtitle.IsSuccess())
                       {
                           return (-1, name);
                       }*/
            }
            Elastic.Clients.Elasticsearch.BulkResponse bulkResponse = client.Bulk(bd =>
                bd.IndexMany(
                    subtitleList,
                    (descriptor, subtitle) =>
                        descriptor
                            .Index(SearchSubtitleCommands.SUBTITLE_INDEX)
                            .Id(subtitle.nameId + "_" + subtitle.chapter + "_" + subtitle.numb)
                )
            );
            if (bulkResponse.IsSuccess()) { }
            /*foreach (Subtitle sub in subtitles)
            {
                SearchSubtitle subtitle = new SearchSubtitle()
                {
                    numb = sub.Number,
                    text = sub.Text,
                    start = $"{sub.StartTime:hh\\:mm\\:ss\\,fff}",
                    end = $"{sub.EndTime:hh\\:mm\\:ss\\,fff}",
                    nameId = name.nameId,
                    chapter = int.Parse(fileInfo.Name.ToLower().Replace(".srt", ""))
                };
                string _id = subtitle.nameId + "_" + subtitle.chapter + "_" + subtitle.numb;
                subtitleList.Add(subtitle);
                Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle> ir
                    = new Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle>(subtitle, SubtitleSearchUI.SUBTITLE_INDEX, _id);
                var responseSubtitle = client.Index(ir);
                if (!responseSubtitle.IsSuccess())
                {
                    return (-1,name);
                }
            }*/
            name.count = name.count + subtitles.Count;
            Log.Information(fileInfo.FullName + "已导入" + subtitles.Count);
            return (subtitles.Count, name);
        }

        public override void updateCount(Dictionary<string, SubtitleName> nameMap)
        {
            foreach (var nm in nameMap.Values)
            {
                Elastic.Clients.Elasticsearch.IndexRequest<SubtitleName> ir =
                    new Elastic.Clients.Elasticsearch.IndexRequest<SubtitleName>(
                        nm,
                        SearchSubtitleCommands.NAME_INDEX,
                        nm.nameId
                    );
                var responseIndex = client.Index(ir);
                Log.Information("更新" + nm.name + "数据量" + nm.count);
                if (responseIndex.IsValidResponse) { }
            }
        }
    }

    /// <summary>
    /// 电影的字幕处理方式
    /// </summary>
    public class SubtitleImportMovieService : ISubtitleImportService
    {
        public SubtitleImportMovieService()
        {
            this.searchType = SubtitleSearchType.Movie;
        }

        public SubtitleImportMovieService(SubtitleSearchType searchType)
        {
            this.searchType = searchType;
        }

        public override (string folder, List<string> files) open(bool batch = false)
        {
            List<string> fileList = new List<string>();
            OpenFileDialog openFileDialog = new OpenFileDialog();
            string filter = "字幕文件(*.srt,*.ass,*.ssa)|*.srt;*.ass;*.ssa";
            openFileDialog.Filter = filter;
            openFileDialog.RestoreDirectory = true;
            openFileDialog.FilterIndex = 1;
            openFileDialog.Multiselect = true;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string[] fileNames = openFileDialog.FileNames;
                string directoryName = null;
                foreach (string filePath in fileNames)
                {
                    FileInfo fileInfo = new FileInfo(filePath);
                    directoryName = fileInfo.DirectoryName;
                    if (fileInfo.Name.ToLower().EndsWith(".srt"))
                    {
                        fileList.Add(fileInfo.Name);
                    }
                    else if (fileInfo.Name.ToLower().EndsWith(".ass"))
                    {
                        fileList.Add(fileInfo.Name.ToLower().Replace(".ass", ".srt"));
                    }
                    else if (fileInfo.Name.ToLower().EndsWith(".ssa"))
                    {
                        fileList.Add(fileInfo.Name.ToLower().Replace(".ssa", ".srt"));
                    }
                    assToSrt(directoryName);
                }

                return (directoryName, fileList);
            }
            return (null, null);
        }

        public override (int count,SubtitleName name) importSubtitle(
            string folder,
            SubtitleImport file,
            string address
        )
        {
            string sname = file.FileName.Replace(".srt", "");
            SubtitleName name = nameMap[sname];
            string path = folder + "\\" + file.FileName;
            FileInfo fileInfo = new FileInfo(path);
            List<Subtitle> subtitles = SubtitleUtils.ReadSubtitle(fileInfo);
            List<SearchSubtitle> subtitleList = new List<SearchSubtitle>();
            foreach (Subtitle sub in subtitles)
            {
                SearchSubtitle subtitle = new SearchSubtitle()
                {
                    numb = sub.Number,
                    text = sub.Text,
                    start = $"{sub.StartTime:hh\\:mm\\:ss\\,fff}",
                    end = $"{sub.EndTime:hh\\:mm\\:ss\\,fff}",
                    nameId = name.nameId,
                    chapter = 1,
                };
                string _id = subtitle.nameId + "_" + subtitle.chapter + "_" + subtitle.numb;
                subtitleList.Add(subtitle);
                /*Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle> ir = new Elastic.Clients.Elasticsearch.IndexRequest<SearchSubtitle>(subtitle, SubtitleSearchUI.SUBTITLE_INDEX, _id);
                var responseSubtitle = base.client.Index(ir);
                if (!responseSubtitle.IsValidResponse)
                {
                    Log.Information("异常");
                    return (-1,name);
                }*/
            }
            Elastic.Clients.Elasticsearch.BulkResponse bulkResponse = client.Bulk(bd =>
                bd.IndexMany(
                    subtitleList,
                    (descriptor, subtitle) =>
                        descriptor
                            .Index(SearchSubtitleCommands.SUBTITLE_INDEX)
                            .Id(subtitle.nameId + "_" + subtitle.chapter + "_" + subtitle.numb)
                )
            );
            if (bulkResponse.IsSuccess()) { }
            name.count = subtitles.Count;
            Log.Information(fileInfo.FullName + "已导入" + subtitles.Count);
            return (subtitles.Count, name);
        }

        public override void updateCount(Dictionary<string, SubtitleName> nameMap)
        {
            foreach (SubtitleName nm in nameMap.Values)
            {
                Elastic.Clients.Elasticsearch.IndexRequest<SubtitleName> ir =
                    new Elastic.Clients.Elasticsearch.IndexRequest<SubtitleName>(
                        nm,
                        SearchSubtitleCommands.NAME_INDEX,
                        nm.nameId
                    );
                var responseIndex = base.client.Index(ir);
                Log.Information("更新" + nm.name + "数据量" + nm.count);

                if (responseIndex.IsValidResponse) { }
            }
        }
    }
}
